﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XQ.Framework.WeChat
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Net;
    using System.Net.Http;
    using System.Security.Cryptography;
    using System.Security.Cryptography.X509Certificates;
    using System.Text;
    using System.Threading.Tasks;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;

    public class WeChatPayV3Service
    {
        // 配置参数
        public string MchId { get; set; }             // 服务商商户号
        public string AppId { get; set; }             // 服务商AppID
        public string SubMchId { get; set; }          // 子商户号
        public string SubAppId { get; set; }          // 子商户AppID (可选)
        public string ApiKeyV3 { get; set; }          // API v3密钥
        public string CertSerialNo { get; set; }      // 证书序列号
        public string PrivateKey { get; set; }        // 商户私钥 (PEM格式)
        public string NotifyUrl { get; set; }         // 支付通知地址

        // 微信支付API域名
        private const string WECHAT_PAY_API = "https://api.mch.weixin.qq.com";

        /// <summary>
        /// 服务商模式JSAPI下单
        /// </summary>
        public async Task<Dictionary<string, string>> CreateJsapiOrder(
            string openId,
            string orderId,
            int totalFee,
            string description,
            string ip,
            bool isServiceMode = true)
        {
            var url = $"{WECHAT_PAY_API}/v3/pay/partner/transactions/jsapi";

            var body = new
            {
                sp_appid = AppId,
                sp_mchid = MchId,
                sub_appid = isServiceMode ? SubAppId : null,
                sub_mchid = isServiceMode ? SubMchId : null,
                description = description,
                out_trade_no = orderId,
                time_expire = DateTime.Now.AddMinutes(15).ToString("yyyy-MM-ddTHH:mm:sszzz"),
                amount = new
                {
                    total = totalFee,
                    currency = "CNY"
                },
                payer = new
                {
                    sp_openid = isServiceMode ? null : openId, // 服务商模式时使用子商户openid
                    sub_openid = isServiceMode ? openId : null // 服务商模式时使用子商户openid
                },
                notify_url = NotifyUrl
            };

            var response = await RequestV3Async(url, HttpMethod.Post, body);
            var result = JsonConvert.DeserializeObject<JObject>(response);

            if (result["prepay_id"] == null)
                throw new Exception($"下单失败: {result}");

            string prepayId = result["prepay_id"].ToString();
            return GenerateMiniProgramParams(prepayId, isServiceMode);
        }

        /// <summary>
        /// 生成小程序支付参数
        /// </summary>
        private Dictionary<string, string> GenerateMiniProgramParams(string prepayId, bool isServiceMode)
        {
            string timestamp = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
            string nonceStr = Guid.NewGuid().ToString("N").Substring(0, 32);
            string package = $"prepay_id={prepayId}";

            // 服务商模式下，支付使用的appId是子商户AppId
            string appId = isServiceMode && !string.IsNullOrEmpty(SubAppId)
                ? SubAppId
                : AppId;

            // 构造签名串
            string message = $"{appId}\n{timestamp}\n{nonceStr}\n{package}\n";
            string signature = Sign(message);

            return new Dictionary<string, string>
            {
                ["appId"] = appId,
                ["timeStamp"] = timestamp,
                ["nonceStr"] = nonceStr,
                ["package"] = package,
                ["signType"] = "RSA",
                ["paySign"] = signature
            };
        }

        /// <summary>
        /// 服务商模式分账
        /// </summary>
        public async Task<JObject> ProfitSharing(
            string transactionId,
            string outOrderNo,
            List<Receiver> receivers)
        {
            var url = $"{WECHAT_PAY_API}/v3/profitsharing/orders";

            var body = new
            {
                sub_mchid = SubMchId,
                transaction_id = transactionId,
                out_order_no = outOrderNo,
                receivers = receivers
            };

            var response = await RequestV3Async(url, HttpMethod.Post, body);
            return JsonConvert.DeserializeObject<JObject>(response);
        }

        /// <summary>
        /// 服务商模式退款
        /// </summary>
        public async Task<JObject> CreateRefund(
            string transactionId,
            string outRefundNo,
            int totalFee,
            int refundFee,
            string reason = "")
        {
            var url = $"{WECHAT_PAY_API}/v3/refund/domestic/refunds";

            var body = new
            {
                transaction_id = transactionId,
                out_refund_no = outRefundNo,
                reason = reason,
                amount = new
                {
                    refund = refundFee,
                    total = totalFee,
                    currency = "CNY"
                }
            };

            var response = await RequestV3Async(url, HttpMethod.Post, body);
            return JsonConvert.DeserializeObject<JObject>(response);
        }

        /// <summary>
        /// 验证支付回调签名
        /// </summary>
        public bool ValidateCallback(string wechatpaySignature, string wechatpayTimestamp,
                                    string wechatpayNonce, string body)
        {
            // 构造验签名串
            string message = $"{wechatpayTimestamp}\n{wechatpayNonce}\n{body}\n";

            // 获取微信支付平台公钥
            string publicKey = GetWechatPublicKey();

            // 验证签名
            using (var rsa = RSA.Create())
            {
                rsa.ImportFromPem(publicKey);
                byte[] data = Encoding.UTF8.GetBytes(message);
                byte[] signatureBytes = Convert.FromBase64String(wechatpaySignature);
                return rsa.VerifyData(data, signatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
            }
        }

        /// <summary>
        /// 执行V3 API请求
        /// </summary>
        private async Task<string> RequestV3Async(string url, HttpMethod method, object body = null)
        {
            using (var handler = new HttpClientHandler())
            {
                // 配置证书 (退款/分账等敏感操作需要)
                if (url.Contains("/secapi/"))
                {
                    var cert = new X509Certificate2("path_to_cert.p12", "mch_id",
                        X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
                    handler.ClientCertificates.Add(cert);
                }

                using (var client = new HttpClient(handler))
                {
                    // 构造请求
                    var request = new HttpRequestMessage(method, url);

                    // 添加认证头
                    string token = GenerateToken(method, url, body);
                    request.Headers.Add("Authorization", $"WECHATPAY2-SHA256-RSA2048 {token}");

                    // 添加商户信息
                    request.Headers.Add("Accept", "application/json");
                    request.Headers.Add("Content-Type", "application/json");
                    request.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
                    request.Headers.Add("Wechatpay-Serial", CertSerialNo);

                    // 添加请求体
                    if (body != null)
                    {
                        string json = JsonConvert.SerializeObject(body);
                        request.Content = new StringContent(json, Encoding.UTF8, "application/json");
                    }

                    // 发送请求
                    var response = await client.SendAsync(request);
                    string responseContent = await response.Content.ReadAsStringAsync();

                    if (!response.IsSuccessStatusCode)
                        throw new Exception($"请求失败: {response.StatusCode}, {responseContent}");

                    return responseContent;
                }
            }
        }

        /// <summary>
        /// 生成认证Token
        /// </summary>
        private string GenerateToken(HttpMethod method, string url, object body = null)
        {
            string timestamp = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
            string nonce = Guid.NewGuid().ToString("N");

            // 获取请求体 (GET请求无请求体)
            string bodyString = "";
            if (method != HttpMethod.Get && body != null)
                bodyString = JsonConvert.SerializeObject(body);

            // 构造签名串
            string path = new Uri(url).PathAndQuery;
            string message = $"{method.Method}\n{path}\n{timestamp}\n{nonce}\n{bodyString}\n";

            // 计算签名
            string signature = Sign(message);

            // 构造Token
            return $"mchid=\"{MchId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{CertSerialNo}\",signature=\"{signature}\"";
        }

        /// <summary>
        /// RSA签名
        /// </summary>
        private string Sign(string message)
        {
            using (var rsa = RSA.Create())
            {
                rsa.ImportFromPem(PrivateKey);

                byte[] data = Encoding.UTF8.GetBytes(message);
                byte[] signature = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
                return Convert.ToBase64String(signature);
            }
        }

        /// <summary>
        /// 获取微信支付平台公钥
        /// </summary>
        private string GetWechatPublicKey()
        {
            // 实际应从微信支付平台证书接口获取，此处仅示例
            // 详见：https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay5_1.shtml
            return @"-----BEGIN PUBLIC KEY-----
        MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo
        4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u
        +qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh
        kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ
        0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg
        cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc
        mwIDAQAB
        -----END PUBLIC KEY-----";
        }
    }

    /// <summary>
    /// 分账接收方
    /// </summary>
    public class Receiver
    {
        [JsonProperty("type")]
        public string Type { get; set; } // MERCHANT_ID/PERSONAL_OPENID

        [JsonProperty("account")]
        public string Account { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; } // 需加密

        [JsonProperty("amount")]
        public int Amount { get; set; }

        [JsonProperty("description")]
        public string Description { get; set; }
    }
}
